#include "AST_XLab2.h"

// expr
expr::expr() {
};
expr::expr( EXPRESSION_TYPE e ) {
	this->_expr_type = e;

};
expr::expr ( OP_TYPE operation_type ) {
	OP_TYPE op = operation_type;
	switch(op) {
	case OP_Plus:
		this->_expr_type = EXPRESSION_Plus;
		break;
	case OP_Minus:
		this->_expr_type = EXPRESSION_Minus;
		break;
	case OP_Times:
		this->_expr_type = EXPRESSION_Times;
		break;
	default:
		break;
	};
};
EXPRESSION_TYPE expr::getExpr_type() {
	return this->_expr_type;
};
void expr::setExprString( STRING s ){
	this->_expr_string = s;
};
STRING expr::toString() {
	return this->_expr_string;
};


// numeric_expr
numeric_expr::numeric_expr ( VAR_INDEX id ){
	this->_expr_id = id;
	char c[100];
	itoa(id, c, 10);
	STRING s = c;
	//s[0] = c;
	this->setExprString( s );
	this->_id = id;
};



// composite expression
composite_expr::composite_expr ( OP_TYPE operation_type ) 
	: expr ( operation_type ) {
		switch ( operation_type ) {
		case OP_Plus:
			this->setExprString("+");
			break;
		case OP_Minus:
			this->setExprString("-");
			break;
		case OP_Times:
			this->setExprString("*");
			break;
		default:
			this->setExprString("#");
			break;
		};
		this->_lhs = NULL;
		this->_rhs = NULL;
};
void composite_expr::setRHS ( expr *e ) {
	this->_rhs = e;
};
void composite_expr::setLHS ( expr *e ) {
	this->_lhs = e;
};
expr* composite_expr::getRHS() {
	return this->_rhs;
};
expr* composite_expr::getLHS() {
	return this->_lhs;
};



// stmtNode
stmtNode::stmtNode( STATEMENT_TYPE st ) {
	//cout << "stmt2 constructor: " << sizeof(LINK_TYPE) << endl;
	this->_stmtIndex = -1;
	this->stmtType = st;
	_nextNode = NULL;
	_followsNode = NULL;
	_prevNode = NULL;
	for( int i=0; i<numLinks; i++ ) {
		links[i] = NULL;
	}
};
INDEX stmtNode::getStmtIndex() {
	return this->_stmtIndex;
};
STATEMENT_TYPE stmtNode::getStmtType(){
	return this->stmtType;
};
void stmtNode::setLink( LINK_TYPE l, stmtNode* s ) {
	(this->links)[l] = s;
};



// assignment stmtNode
assignment_stmtNode::assignment_stmtNode( STATEMENT_INDEX id, VAR_INDEX variable_id, PROC_INDEX curr_p_id) : stmtNode( STATEMENT_Assign ) {
	this->_stmtIndex = id;
	this->_proc_id = curr_p_id;
	this->_lhs = new numeric_expr ( variable_id );
};
expr* assignment_stmtNode::getLHS () {
	return _lhs;
};
expr* assignment_stmtNode::getRHS () {
	return this->_rhs;
};
void assignment_stmtNode::setLHS ( expr *e ) {
	this->_lhs = e;
};
void assignment_stmtNode::setRHS ( expr *e ) {
	this->_rhs = e;
};



// call stmtNode
call_stmtNode::call_stmtNode( STATEMENT_INDEX id, PROC_INDEX called_proc_id, PROC_INDEX curr_p_id ) : stmtNode( STATEMENT_Call ) {
	this->_stmtIndex = id;
	this->_proc_id = curr_p_id;
	this->_called_procedure_ID = called_proc_id;
};
VAR_INDEX call_stmtNode::getCallProcID () {
	return this->_called_procedure_ID;
};



// if stmtNode
if_stmtNode::if_stmtNode(  INDEX id, VAR_INDEX condition_variable, PROC_INDEX curr_p_id ) : stmtNode( STATEMENT_If ) {
		this->_stmtIndex = id;
		this->_proc_id = curr_p_id;
		this->_condition_variable = condition_variable;
	};
VAR_INDEX if_stmtNode::getConditionVar (){
		return this->_condition_variable;
	};



// while stmtNode
while_stmtNode::while_stmtNode( INDEX id, VAR_INDEX condition_variable, PROC_INDEX curr_p_id) : stmtNode( STATEMENT_While ) {
		this->_stmtIndex = id;
		this->_proc_id = curr_p_id;
		this->_condition_variable = condition_variable;
		this->_while_stmt_block_head = NULL;
	};
stmtNode** while_stmtNode::_getWhileStmtHead() {
		return &_while_stmt_block_head;
	};
VAR_INDEX while_stmtNode::getConditionVar () {
		return this->_condition_variable;
	};



// AST
void AST::addStmt( stmtNode *newStmt) {
	if( newStmt != NULL ) {
		if ( newStmt->_proc_id == this->_procedure_box.back()->_procedure_id ) {
			this->_stmts.push_back(newStmt);
		}
	} else
		cout << "\nadd new statement error " << endl;
	
};
INTEGER AST::numStmts () {
	return this->_stmts.size();
};
stmtNode* AST::StmtAt ( INDEX id ) {
	if( id < this->_stmts.size())
		return (this->_stmts.at(id));
	else 
		return NULL;
};